﻿using Athena.Observer;
using MassTransit;
using MassTransit.RabbitMqTransport;
using MassTransit.Util;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;

namespace Athena
{
    public class RabbitMqBus : IDisposable
    {
        private static RabbitMqPRCTypeCache _cache;
        private IReceiveObserver _receiveObserver;
        private ILogger _logger;

        private Dictionary<string, RabbitMqBusDispatcher> _busDispatchers;

        public RabbitMqBus(ILogger logger)
        {
            _logger = logger;
            _cache = new RabbitMqPRCTypeCache();
            _busDispatchers = new Dictionary<string, RabbitMqBusDispatcher>();
            _receiveObserver = new DefaultConnectReceiveObserver(logger);
        }

        public RabbitMqBus(ILogger logger, IReceiveObserver receiveObserver)
        {
            _logger = logger;
            _cache = new RabbitMqPRCTypeCache();
            _busDispatchers = new Dictionary<string, RabbitMqBusDispatcher>();
            _receiveObserver = receiveObserver;
        }

        public RabbitMqBus(ILogger logger, IReceiveObserver receiveObserver, string testDLLPath)
        {
            _logger = logger;
            _cache = new RabbitMqPRCTypeCache(testDLLPath);
            _busDispatchers = new Dictionary<string, RabbitMqBusDispatcher>();
            _receiveObserver = receiveObserver;
        }

        public RabbitMqBus(ILogger logger, string testDLLPath)
        {
            _logger = logger;
            _cache = new RabbitMqPRCTypeCache(testDLLPath);
            _busDispatchers = new Dictionary<string, RabbitMqBusDispatcher>();
            _receiveObserver = new DefaultConnectReceiveObserver(logger);
        }


        private RabbitMqBusDispatcher LoadBusDispatcher(string virtualHost, string exchangeType = "", Tuple<string, Action<IRabbitMqReceiveEndpointConfigurator>> receiveEndpointConfigurator = null)
        {
            //virtualHost = virtualHost.Equals("ucity_log") ? virtualHost : "defaultVirtual";
            RabbitMqBusDispatcher dispatcher = null;
            exchangeType = string.IsNullOrWhiteSpace(exchangeType) ? string.Empty : exchangeType;
            if (_busDispatchers.ContainsKey(virtualHost + exchangeType))
            {
                dispatcher = _busDispatchers[virtualHost + exchangeType];
            }
            else
            {
                dispatcher = new RabbitMqBusDispatcher(_logger, virtualHost, exchangeType);
                _busDispatchers.Add(virtualHost + exchangeType, dispatcher);
            }

            if (receiveEndpointConfigurator != null)
            {
                dispatcher.Add(receiveEndpointConfigurator);
            }
            return dispatcher;
        }

        /// <summary>
        /// 加载 conusmer
        /// </summary>
        /// <returns></returns>
        private async Task LoadConsumer(Action<IRabbitMqBusFactoryConfigurator> startRabbitMqBusFactoryConfigurator = null)
        {
            foreach (var item in _cache.ConsumerCache)
            {
                _logger.LogInformation($"Creating... Consumer {item.Key}");
                var rabbitMqUriAttribute = item.Key.GetCustomAttribute<RabbitMqUriAttribute>();
                if (rabbitMqUriAttribute == null || string.IsNullOrWhiteSpace(rabbitMqUriAttribute.VirtualHost) || string.IsNullOrWhiteSpace(rabbitMqUriAttribute.Queue))
                {
                    continue;
                }
                var dispatcher = LoadBusDispatcher(rabbitMqUriAttribute.VirtualHost, rabbitMqUriAttribute.ExchangeType, new Tuple<string, Action<IRabbitMqReceiveEndpointConfigurator>>(rabbitMqUriAttribute.Queue, (rabbitMqReceiveEndpointConfigurator) =>
                  {
                      rabbitMqReceiveEndpointConfigurator.Consumer(item.Key, (type) =>
                      {
                          return item.Value;
                      });

                  }));
            }
            foreach (var item in _busDispatchers)
            {
                await item.Value.Start(_receiveObserver, startRabbitMqBusFactoryConfigurator);
            }
        }

        /// <summary>
        /// 加载 publish
        /// </summary>
        /// <returns></returns>
        private async Task LoadPublish(Action<IRabbitMqBusFactoryConfigurator> startRabbitMqBusFactoryConfigurator = null)
        {
            foreach (var item in _cache.PublishCache)
            {
                _logger.LogInformation($"Initialization... {item.Key.Name}  Publish");
                var rabbitMqUriAttribute = item.Key.GetCustomAttribute<RabbitMqUriAttribute>();
                if (rabbitMqUriAttribute == null || string.IsNullOrWhiteSpace(rabbitMqUriAttribute.VirtualHost) || string.IsNullOrWhiteSpace(rabbitMqUriAttribute.Exchange))
                {
                    continue;
                }
                var bus = LoadBusDispatcher(rabbitMqUriAttribute.VirtualHost, rabbitMqUriAttribute.ExchangeType);
                if (!bus.IsStart)
                {
                    await bus.Start(_receiveObserver, startRabbitMqBusFactoryConfigurator);

                }
                var sendEndpointUri = new Uri(bus.Host.Settings.HostAddress.ToString() + "/" + rabbitMqUriAttribute.Exchange);
                var sendEndpoint = await bus.BusControl.GetSendEndpoint(sendEndpointUri);
                item.Value.Initialization(sendEndpoint);
            }
        }

        /// <summary>
        /// 加载 request
        /// </summary>
        private async Task LoadRequest(Action<IRabbitMqBusFactoryConfigurator> startRabbitMqBusFactoryConfigurator = null)
        {
            try
            {
                foreach (var item in _cache.RequestClientCache)
                {
                    _logger.LogInformation($"Creating... {item.Key.Name}  Request");
                    var rabbitMqUriAttribute = item.Key.GetCustomAttribute<RabbitMqUriAttribute>();
                    if (rabbitMqUriAttribute == null || string.IsNullOrWhiteSpace(rabbitMqUriAttribute.VirtualHost))
                    {
                        continue;
                    }
                    var bus = LoadBusDispatcher(rabbitMqUriAttribute.VirtualHost, rabbitMqUriAttribute.ExchangeType);
                    if (!bus.IsStart)
                    {
                        await bus.Start(_receiveObserver, startRabbitMqBusFactoryConfigurator);
                    }

                    item.Value.CreateClient(bus.BusControl, new Uri(bus.BusControl.Address, rabbitMqUriAttribute.Queue));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public bool Start(Action<IRabbitMqBusFactoryConfigurator> startRabbitMqBusFactoryConfigurator = null)
        {
            TaskUtil.Await(() => LoadConsumer(startRabbitMqBusFactoryConfigurator));
            TaskUtil.Await(() => LoadRequest(startRabbitMqBusFactoryConfigurator));
            TaskUtil.Await(() => LoadPublish(startRabbitMqBusFactoryConfigurator));
            //_busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
            //{
            //    var host = cfg.Host(new Uri(HostUri), h =>
            //    {
            //        h.Username("itvm_rmq");
            //        h.Password("y4yh69t");
            //    });

            //    foreach (var item in _cache.ConsumerCache)
            //    {
            //        _log.Info($"Creating... Consumer {item.Key}");
            //        var uri = item.Key.GetCustomAttribute<RabbitMqUriAttribute>();
            //        if (uri == null || string.IsNullOrWhiteSpace(uri.Queue))
            //        {
            //            continue;
            //        }
            //        cfg.ReceiveEndpoint(host, uri.Queue, rec =>
            //        {
            //            rec.Consumer(item.Key, (type) =>
            //            {
            //                return item.Value;
            //            });
            //        });
            //    }
            //});
            //TaskUtil.Await(() => _busControl.StartAsync());

            //foreach (var item in _cache.PublishCache)
            //{
            //    _log.Info($"Initialization... {item.Key.Name}  Publish");
            //    var uri = item.Key.GetCustomAttribute<RabbitMqUriAttribute>();
            //    if (uri == null || string.IsNullOrWhiteSpace(uri.Exchange))
            //    {
            //        continue;
            //        throw new NullReferenceException($"{item.Key.Name} Undefined PublishUriAttribute");
            //    }
            //    // item.Value.Initialization(_busControl, new Uri(new Uri(HostUri), uri.Uri).ToString());

            //    IRabbitMqHost host = null;

            //    var ibus = RabbitMqBusFactory.Create(factoryCfg =>
            //    {
            //        host = factoryCfg.Host(new Uri("rabbitmq://service.ditiego.net/"), hostCfg =>
            //        {
            //            hostCfg.Username("itvm_rmq");
            //            hostCfg.Password("y4yh69t");
            //        });
            //    });
            //    var sendUri = host.GetSendAddress(uri.Exchange);
            //    ibus.Start();
            //    var sendEndpoint = ibus.GetSendEndpoint(sendUri).Result;
            //    item.Value.Initialization(sendEndpoint);
            //}

            //foreach (var item in _cache.RequestClientCache)
            //{
            //    _log.Info($"Creating... {item.Key.Name}  Request");
            //    item.Value.CreateClient(_busControl);
            //}
            return true;
        }

        public RabbitMqBusDispatcher GetRabbitMqBusDispatcherByVirtualHost(string virtualHost)
        {
            return _busDispatchers[virtualHost];
        }

        public static T RequestClient<T>() where T : IBaseRequest
        {
            if (_cache == null)
            {
                throw new NullReferenceException("RabbitMQPRCTypeCache is Null");
            }
            return _cache.Request<T>();
        }


        public static T PublishClient<T>() where T : IBasePublish
        {
            if (_cache == null)
            {
                return default(T);
            }
            return _cache.Publish<T>();
        }

        public bool Stop()
        {
            Dispose();
            return true;
        }

        public void Dispose()
        {
            if (_busDispatchers != null)
            {
                foreach (var item in _busDispatchers)
                {
                    item.Value.BusControl.Stop();
                    Console.WriteLine($"{item.Value.BusControl.Address} now stopped ");
                }
                _busDispatchers = null;
                _cache.Dispose();
            }
        }
    }
}
